﻿using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
using System.Diagnostics;
using System.Linq;

namespace fm2
{
	public class DataGridViewEx<T> : DataGridView where T : INodeElement
	{
		public List<T> data = new List<T>();
		PropertyInfo [] propertyInfo = typeof(T).GetProperties();
		public new DataGridViewColumn SortedColumn { get; set; }

		public DataGridViewEx()
		{
			this.Dock = DockStyle.Fill;
			this.RowHeadersWidth = 24;
			this.AllowUserToAddRows = false;
			this.AllowUserToDeleteRows = false;
			this.AllowUserToResizeRows = false;
			this.RowHeadersVisible = false;
			this.RowTemplate.Height = 18;
			this.ReadOnly = true;
			this.AutoGenerateColumns = false;
			this.VirtualMode = true;
			this.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
			this.DefaultCellStyle.SelectionForeColor = this.DefaultCellStyle.ForeColor; 

			foreach(PropertyInfo pInfo in typeof(T).GetProperties()) {
				if (pInfo.Name[0] != '_') {
					int index = this.Columns.Add(pInfo.Name, pInfo.Name);
					this.Columns[index].DataPropertyName = pInfo.Name;
				}
			}
			this.CellValueNeeded += DgvCellValueNeeded;
			this.CellPainting += DgvCellPainting;
			this.ColumnHeaderMouseClick += DgvColumnHeaderMouseClick;
		}
		public void ClearData()
		{
			data.Clear();
			Rows.Clear();
		}
		public void SaveSelected()
		{
			Debug.Assert( RowCount == data.Count );
			for(int i=0; i<RowCount; i++) {
				data[i]._Selected = Rows[i].Selected;
			}
		}
		public void RestoreSelected()
		{
			Debug.Assert( RowCount == data.Count );
			for(int i=0; i<RowCount; i++) {
				Rows[i].Selected = data[i]._Selected;
			}
		}
		void DgvColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
		{
			if (Columns[e.ColumnIndex].SortMode == DataGridViewColumnSortMode.NotSortable) {
				return ;
			}

			SortedColumn = Columns[e.ColumnIndex];
			var columns = from DataGridViewColumn column in Columns where column.Index != e.ColumnIndex select column;  
			foreach(var column in columns) {
				column.HeaderCell.SortGlyphDirection = SortOrder.None;
			}
			SortedColumn.HeaderCell.SortGlyphDirection = SortedColumn.HeaderCell.SortGlyphDirection == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;;

			SaveSelected();
			SortData();
			RestoreSelected();
		}

		Color ColorDeleted = Color.FromArgb(0xff,0xb2,0x7a);
		Color ColorCreated = Color.FromArgb(0xa9,0xff,0x7a);
		Color ColorChanged = Color.FromArgb(0xf5,0xff,0x7a);
		Color ColorExisting = Color.FromArgb(0x7a,0xc4,0xff);
		Color ColorDeletedSelected = Color.FromArgb(0xdf,0x92,0x5a);
		Color ColorCreatedSelected = Color.FromArgb(0x89,0xdf,0x5a);
		Color ColorChangedSelected = Color.FromArgb(0xd5,0xdf,0x5a);
		Color ColorExistingSelected = Color.FromArgb(0x5a,0xb4,0xdf);
		void DgvCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
		{
			if (e.RowIndex >= 0 && e.RowIndex < data.Count) {
				if (data[e.RowIndex].Status == StatusElement.Existing) {
					e.CellStyle.BackColor = ColorExisting;
					e.CellStyle.SelectionBackColor = ColorExistingSelected;
				} else if (data[e.RowIndex].Status == StatusElement.Created) {
					e.CellStyle.BackColor = ColorCreated;
					e.CellStyle.SelectionBackColor = ColorCreatedSelected;
				} else if (data[e.RowIndex].Status == StatusElement.Changed) {
					e.CellStyle.BackColor = ColorChanged;
					e.CellStyle.SelectionBackColor = ColorChangedSelected;
				} else if (data[e.RowIndex].Status == StatusElement.Deleted) {
					e.CellStyle.BackColor = ColorDeleted;
					e.CellStyle.SelectionBackColor = ColorDeletedSelected;
				}
			}
		}
		void DgvCellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
		{
			if (e.RowIndex < data.Count) {
				e.Value = propertyInfo[e.ColumnIndex].GetValue(data[e.RowIndex], null).ToString();
			}
		}
		public void SortData()
		{
			int asc = SortedColumn.HeaderCell.SortGlyphDirection == SortOrder.Ascending ? 1 : -1;
			PropertyInfo pInfo = typeof(T).GetProperty(SortedColumn.HeaderText);
			data.Sort((x, y) => {
				object ox = pInfo.GetValue(x, null);
				object oy = pInfo.GetValue(y, null);
				string sx = ox == null ? "" : ox.ToString();
				string sy = oy == null ? "" : oy.ToString();
				return asc * SafeNativeMethods.StrCmpLogicalW(sx, sy);
			});
			Refresh();
		}
	}
}
